Mybatis框架(3) —— 使用代理持久层实现类实现CRUD操作

简介

  • MyBatis环境搭建 的方式在前面已经详细的介绍过了,本文将通过映射配置文件,使用代理持久层实现类的方式,来进行MySQL数据库的CRUD操作。
  • 环境搭建成功后,MySQL数据库的CRUD操作基于以下几个文件的基础上进行修改:
    • UserDao.java(持久层接口)
      • 添加CRUD操作的抽象方法。
    • UserDao.xml(持久层接口的映射配置文件)
      • 添加持久层接口的全类名:namespace
      • 添加CRUD操作的mapper子标签:select、update、insert、
      • 添加方法名:id
      • 添加返回值类型的全类名:resultType

环境搭建

Maven项目依赖

  • 在pom.xml 文件中,并不引入MyBatis框架的依赖:
    • mybatis(MyBatis框架)
    • mysql-connector-java(数据库连接)
    • junit (单元测试)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>cn.water</groupId>
<artifactId>section03_CRUD_ProxyDao</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
<!-- MyBatis框架 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!-- MySQL 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>

</project>

数据库表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#创建数据库
CREATE DATABASE mybatis;
USE mybatis;

#创建表
CREATE TABLE USER(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32) NOT NULL COMMENT '用户名称',
birthday DATETIME DEFAULT NULL COMMENT '生日',
sex CHAR(1) DEFAULT NULL COMMENT '性别',
address VARCHAR(256) DEFAULT NULL COMMENT '地址'
) ENGINE = INNODB DEFAULT CHARSET = utf8;

#插入数据
INSERT INTO USER VALUES
(41,'老王','2018-02-27 17:47:08','男','北京'),
(42,'小二王','2018-03-02 15:09:37','女','北京金燕龙'),
(43,'小二王','2018-03-04 11:34:34','女','北京金燕龙'),
(45,'传智播客','2018-03-04 12:04:06','男','北京金燕龙'),
(46,'老王','2018-03-07 17:37:26','男','北京'),
(48,'小马宝莉','2018-03-08 11:44:00','女','北京修正');

目录结构

  • src/main
    • java
      • cn/water/dao
        • UserDao.java(持久层接口)
      • cn/water/domain
        • User.java(实体层)
      • resources
        • cn/water/dao
          • UserDao.xml(映射配置文件)
      • SqlMapConfig.xml(MyBatis主配置文件)
  • src/tese
    • java
      • cn/water/test
        • MybatisTest.java(测试文件)

实体类

User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package cn.water.domain;

import java.io.Serializable;
import java.util.Date;

public class User implements Serializable {

/** 成员变量 */
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;

/** 构造方法 */
public User() {

}

public User(Integer id, String username, Date birthday, String sex, String address) {
this.id = id;
this.username = username;
this.birthday = birthday;
this.sex = sex;
this.address = address;
}


/** toString */
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}

/** Getter Setter */
public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public Date getBirthday() {
return birthday;
}

public void setBirthday(Date birthday) {
this.birthday = birthday;
}

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}


}

持久层接口

UserDao.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package cn.water.dao;

import cn.water.domain.User;

import java.util.List;

public interface UserDao {

/** 添加用户 */
void add(User user);

/** 更新用户 */
void update(User user);

/** 删除用户 */
void delete(Integer id);

/** 查询所有用户 */
List<User> findAll();

/** 查询单个用户 */
User findOne(Integer id);

/** 根据姓名模糊查询 */
List<User> findByName(String name);

/** 查询所有用户的数量 */
Integer findTotal();


}

映射配置文件

UserDao.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">


<mapper namespace="cn.water.dao.UserDao">

<!-- 添加用户 -->
<!-- 参数类型 JavaBean,占位符 = 成员变量名的小写形式 -->
<select id="add" parameterType="cn.water.domain.User" >
INSERT INTO user VALUES ( #{id}, #{username}, #{birthday}, #{sex}, #{address} ) ;
</select>

<!-- 更新用户 -->
<select id="update" parameterType="cn.water.domain.User">
UPDATE user SET
username = #{username},
birthday = #{birthday},
sex = #{sex},
address = #{address}
WHERE
id = #{id} ;
</select>

<!-- 删除用户 -->
<!-- 参数类型 基本类型,占位符 = 方法参数名称 -->
<select id="delete" parameterType="INT" >
DELETE FROM user WHERE id = #{id};
</select>

<!-- 查询所有 -->
<select id="findAll" resultType="cn.water.domain.User">
SELECT * FROM user;
</select>

<!-- 查询单个用户 -->
<select id="findOne" parameterType="INT" resultType="cn.water.domain.User">
SELECT * FROM user WHERE id = #{id} ;
</select>

<!-- 根据姓名模糊查询 -->
<select id="findByName" parameterType="java.lang.String" resultType="cn.water.domain.User">
SELECT * FROM user WHERE username LIKE #{name};
</select>
<select id="findByName" parameterType="java.lang.String" resultType="cn.water.domain.User">
SELECT * FROM user WHERE username LIKE '% {value} %';
</select>

<!-- 查询所有用户的数量 -->
<select id="findTotal" resultType="INT" >
SELECT COUNT(*) FROM user;
</select>
</mapper>

测试类

Test.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package cn.water.test;

import cn.water.dao.UserDao;
import cn.water.domain.QueryVo;
import cn.water.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

public class UserTest {

/* 成员变量 */
private InputStream inputStream;
private SqlSession session;
private UserDao dao;

/* 初始化操作 */
@Before
public void init() throws IOException {
/* 加载 MyBatis配置文件 */
inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
/* 获取 工厂类 */
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
/* 获取 产品类 */
session = factory.openSession();
/* 获取 代理对象 */
dao = session.getMapper(UserDao.class);
}

/* 销毁操作 */
@After
public void destroy() throws IOException {
session.close();
inputStream.close();
}


/** 添加用户 */
@Test
public void test01(){
dao.add( new User(100,"ADD",new Date(),"男","UserDao") );
session.commit();
}

/** 更新用户 */
@Test
public void test02(){
dao.update( new User(100,"UPDATE",new Date(),"男","UserDao") );
session.commit();
}

/** 删除用户 */
@Test
public void test03(){
dao.delete(100);
session.commit();
}

/** 查询所有用户 */
@Test
public void test04(){
for (User user : dao.findAll()) {
System.out.println(user);
}
}

/** 查询单个用户 */
@Test
public void test05(){
System.out.println( dao.findOne(41) );
}


/** 根据用户模糊查询 */
@Test
public void test06(){
// LIKE #{username} 使用的是PreparedStatement对象
List<User> userList1 = dao.findByName01("%王%");
// LIKE '%${value}%' 使用的是Statement对象
List<User> userList2 = dao.findByName02("王");
/* 输出 */
for (User user : userList1) {
System.out.println("1--"+user);
}
for (User user : userList2) {
System.out.println("2--"+user);
}
}

/** 查询所有用户的数量 */
@Test
public void test07(){
System.out.println( dao.findTotal() );
}

/** 添加用户 + 返回ID */
@Test
public void test08(){
System.out.println(dao.addReturnID(new User(100, "ADD RETURN", new Date(), "男", "UserDao")));
}

/** 根据QueryVo对象的条件,模糊查询 */
@Test
public void test09(){

for(User user : dao.findByQueryVO(new QueryVo(new User(100, "ADD RETURN", new Date(), "男", "UserDao")))){
System.out.println(user);
}
}


}

实现CRUD操作

  • 在前一篇博客里,我们学习了自定义MyBatis框架,当时我们使用了 Proxy类 和 MapperProxy类 实现了动态代理,并调用了 selectList方法 帮我去执行具体的SQL语句。尽管这并不是完全具体的MyBatis框架底层运作方式,但以目前的知识来讲就足够了。
  • 所以当我们使用代理持久层实现类的方式时,代理对象会帮我去调用 selectList方法;但是当我们使用手动编写持久层实现类的方式时,我们就需要自己去调用 selectList方法了。但关于这方面的事情,我不准备在下面讲,这是下一篇博客的事情了。
  • 本篇博客在实现CRUD操作的章节,主要用于描述 持久层接口和映射配置文件

思维导图

![](3.ProxyDao CRUD操作/MyBatisCRUD操作.png)

添加用户

  • 持久层接口
1
void add(User user);
  • 映射配置文件
1
2
3
<select id="add" parameterType="cn.water.domain.User" >
INSERT INTO user VALUES ( #{id}, #{username}, #{birthday}, #{sex}, #{address} ) ;
</select>

更新用户

  • 持久层接口
1
void update(User user);
  • 映射配置文件
1
2
3
4
5
6
7
8
9
<select id="update" parameterType="cn.water.domain.User">
UPDATE user SET
username = #{username},
birthday = #{birthday},
sex = #{sex},
address = #{address}
WHERE
id = #{id} ;
</select>

删除用户

  • 持久层接口
1
void delete(Integer id);
  • 映射配置文件
1
2
3
<select id="delete" parameterType="INT" >
DELETE FROM user WHERE id = #{id};
</select>

查找所有用户

  • 持久层接口
1
User findOne(Integer id);
  • 映射配置文件
1
2
3
<select id="findAll" resultType="cn.water.domain.User">
SELECT * FROM user;
</select>

查询单个用户

  • 持久层接口
1
List<User> findAll();
  • 映射配置文件
1
2
3
 <select id="findOne" parameterType="INT" resultType="cn.water.domain.User">
SELECT * FROM user WHERE id = #{id} ;
</select>

根据姓名模糊查询

  • 持久层接口
1
2
List<User> findByName01(String name);
List<User> findByName02(String name);
  • 映射配置文件
1
2
3
4
5
6
7
<select id="findByName01" parameterType="java.lang.String" resultType="cn.water.domain.User">
SELECT * FROM user WHERE username LIKE #{username};
</select>

<select id="findByName02" parameterType="java.lang.String" resultType="cn.water.domain.User">
SELECT * FROM user WHERE username LIKE '%${value}%';
</select>

查询所有用户数量

  • 持久层接口
1
Integer findTotal();
  • 映射配置文件
1
2
3
<select id="findTotal" resultType="INT" >
SELECT COUNT(*) FROM user;
</select>

添加用户返回ID

  • 持久层接口
1
2
3
4
5
6
7
8
9
<insert id="addReturnID" parameterType="cn.water.domain.User">
<selectKey keyProperty="id" keyColumn="id" resultType="INT" order="AFTER">
SELECT last_insert_id();
</selectKey>
INSERT INTO
usr
VALUES
(null,#{username},#{birthday},#{sex},#{address});
</insert>
  • 映射配置文件
1
2
3
for(User user : dao.findByQueryVO(new QueryVo(new User(100, "ADD RETURN", new Date(), "男", "UserDao")))){
System.out.println(user);
}

【OGNL表达式】

  • Object Graphic Navigation Language:对象图导航语言
    • 获取数据的一种表达式,在形式上省略了get
      • Java表达式:user.getUsername();
      • OGNL表达式:user.username
      • MyBatis表达式:username
  • 其实在MyBatis的映射配置文件中,我们使用的也是OGNL表达式。只是由于我们再 parameterType属性中已经提供了实体类,所以我们可以省略实体类名直接使用属性名来获取数据。

【POJO对象】

  • POJO对象等同于JavaBean对象,属于实体类的一种。
  • 我们通过User对象来传递查询条件时,查询条件的范围有限,只能是User对象中有的数据。但在实际操作中,除了需要User对象的查询条件,还会需要其他对象的查询条件,此时使用User对象来传递查询条件显然是不够的。
  • 通过POJO对象来传递查询条件的优势正在于此,将User对象以及所需的其他对象作为成员变量封装进POJO对象,在查询时,就可以使用多个对象的查询条件。

根据Query对象的条件,模糊查询

  • QueryVo对象
    • 将User对象封装进QueryVo对象中,并通过QueryVo对象来获取User对象中Username的值,用于进行模糊查询。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package cn.water.domain;

public class QueryVo {

/* 成员变量 */
private User user;

/* 构造方法 */
public QueryVo(User user) {
this.user = user;
}

/* Getter Setter */
public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}
}
  • 持久层接口
1
List<User> findByQueryVO(QueryVo queryVo);
  • 映射配置文件
1
2
3
<select id="findByQueryVo" parameterType="cn.water.domain.QueryVo" resultType="cn.water.domain.User">
SELECT * FROM user WHERE username LIKE #{user.username};
</select>

执行过程(思维导图)

![](3.ProxyDao CRUD操作/ProxyDao CRUD操作 底层.png)

-------------本文结束-------------
Donate comment here